package io.yunho.yunho.interview.two.thread;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author: yunho
 * @date: 2021/7/29 9:35
 * @description:
 */
public class ThreadDemo {
    public static void main(String[] args) {
//        for(int i=0;i<3;i++){
//            new Thread(()->{
//                new ExtendThread().run();
//            },String.valueOf(i)).start();
//        }
//        for(int i=0;i<3;i++){
//            new Thread(()->{
//                new ExtendRunable().run();
//            },String.valueOf(i)).start();
//        }
//        ExtendCallable extendCallable = new ExtendCallable();
//        try {
//            Integer call = extendCallable.call();
//            System.out.println(call);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        //需要FutureTask的支持 用于接收运算结果 也可以用用于闭锁
        /**
         * FutureTask可用于异步获取执行结果或取消执行任务的场景。
         * 经过传入Runnable或者Callable的任务给FutureTask，
         * 直接调用其run方法或者放入线程池执行，
         * 以后能够在外部经过FutureTask的get方法异步获取执行结果，所以，
         * FutureTask很是适合用于耗时的计算，主线程能够在完成本身的任务后，
         * 再去获取结果。另外，FutureTask还能够确保即便调用了屡次run方法，
         * 它都只会执行一次Runnable或者Callable任务，或者经过cancel取消FutureTask的执行等
         * 两种常见场景
         * 1、多个并行任务同时计算，统计汇总结果
         */
        // 建立任务集合
        List<FutureTask<Integer>> taskList = new ArrayList<FutureTask<Integer>>();
        // 建立线程池
        ExecutorService exec = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            // 传入Callable对象建立FutureTask对象
            FutureTask<Integer> ft = new FutureTask<Integer>(new ExtendCallable());
            taskList.add(ft);
            // 提交给线程池执行任务，也能够经过exec.invokeAll(taskList)一次性提交全部任务;
            exec.submit(ft);
        }
        System.out.println("全部计算任务提交完毕, 主线程接着干其余事情！");

        // 开始统计各计算线程计算结果
        Integer totalResult = 0;
        for (FutureTask<Integer> ft : taskList) {
            try {
                //FutureTask的get方法会自动阻塞,直到获取计算结果为止
                totalResult = totalResult + ft.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        // 关闭线程池
        exec.shutdown();
        System.out.println("多任务计算后的总结果是:" + totalResult);
        /**
         * 2、保证高并发情况下，某些任务只执行一次
         * 传统的我们可以通过加锁的方式进行，这里我们采用futureTask
         */
        FuntureTaskDemo funtureTaskDemo = new FuntureTaskDemo();
        for(int i=0;i<10;i++){
            new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName()+"\t"+funtureTaskDemo.getConnection("mm"));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}

/**
 * 创建执行线程的第一种方式，不建议
 */
class  ExtendThread extends Thread{
    @Override
    public void run() {
//        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"\ti****** \t");
//        }
    }
}
class ExtendRunable implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"\ti****** \t");
    }
}

/**
 * 第三种方式，与前两种相比，有返回值，并且可以异步延迟获取，需要借助futureTask
 */
class ExtendCallable implements Callable<Integer>{

    public ExtendCallable(){
        System.out.println("生成子线程计算任务：\t"+Thread.currentThread().getName());
    }

    @Override
    public Integer call() throws Exception {
        System.out.println("执行计算******start********");
        for (int i = 0; i < 100; i++) {
        }
        //每次计算延迟5秒
        try {
            TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}
        System.out.println("执行计算******end********");
        return 100;
    }
}
class InnerConnection{
    public InnerConnection(String url) {
        this.url = url;
    }

    private String url;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}
class FuntureTaskDemo{
    private ConcurrentHashMap<String, FutureTask<InnerConnection>> connectionPool = new ConcurrentHashMap<String, FutureTask<InnerConnection>>();

    public InnerConnection getConnection(String key) throws Exception {
        FutureTask<InnerConnection> connectionTask = connectionPool.get(key);
        if (connectionTask != null) {
            return connectionTask.get();
        } else {
            Callable<InnerConnection> callable = new Callable<InnerConnection>() {
                @Override
                public InnerConnection call() throws Exception {
                    // TODO Auto-generated method stub
                    return createConnection();
                }
            };
            FutureTask<InnerConnection> newTask = new FutureTask<InnerConnection>(callable);
            connectionTask = connectionPool.putIfAbsent(key, newTask);
            if (connectionTask == null) {
                connectionTask = newTask;
                connectionTask.run();
            }
            return connectionTask.get();
        }
    }

    //建立Connection
    private InnerConnection createConnection() {
        System.out.println("阻塞中************");
        try {TimeUnit.SECONDS.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
        System.out.println("阻塞结束************");
        return new InnerConnection("9999");
    }
}